#include <stdio.h>
#include <string.h>
#include "openssl/aes.h"
#include <openssl/pem.h>
#include <openssl/bio.h>
/** 根据十六进制字符c计算出其对应的数值
 * @param c 十六进制字符
 * @return 字符对应的值
 */
unsigned char get_value(unsigned char c)
{
    if(c>='0'&&c<='9')
        return c-'0';
    else if(c>='A'&&c<='Z')
        return c-'A'+10;
    else
        return c-'a'+10;
} 
/** 根据字符串设置密钥，密钥中的字符未必是可见字符
 * @param key_str 十六进制字符串
 * @param key 密钥字符串
 */
void set_key(char * key_str,unsigned char key[17])
{
    unsigned char temp[2];
    for(int i=0;i<16;i++)
    {
        strncpy(temp,key_str+i*2,2);
        key[i]=get_value(temp[0])*16+get_value(temp[1]);
        //printf("temp[0]=%d temp[1]=%d value=%d\n",temp[0],temp[1],key[i]);
    }
    key[16]='\0';
}
/** 对字符串进行base64编码
 * @param in_str 待编码字符串
 * @param in_len 待编码字符串长度
 * @param out_str 编码后的输出字符串
 * @return 输出字符串
 */
int base64_encode(char *in_str, int in_len, char *out_str)
{
    BIO *b64, *bio;
    BUF_MEM *bptr = NULL;
    size_t size = 0;
 
    if (in_str == NULL || out_str == NULL)
        return -1;
 
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);
 
    BIO_write(bio, in_str, in_len);
    BIO_flush(bio);
 
    BIO_get_mem_ptr(bio, &bptr);
    memcpy(out_str, bptr->data, bptr->length);
    out_str[bptr->length] = '\0';
    size = bptr->length;
 
    BIO_free_all(bio);
    return size;
}
/** 对字符串进行base64解码
 * @param in_str 待解码字符串
 * @param in_len 待解码字符串长度
 * @param out_str 解码后的输出字符串
 * @return 输出字符串
 */
int base64_decode(char *in_str, int in_len, char *out_str)
{
    BIO *b64, *bio;
    BUF_MEM *bptr = NULL;
    int counts;
    int size = 0;
 
    if (in_str == NULL || out_str == NULL)
        return -1;
 
    b64 = BIO_new(BIO_f_base64());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
 
    bio = BIO_new_mem_buf(in_str, in_len);
    bio = BIO_push(b64, bio);
 
    size = BIO_read(bio, out_str, in_len);
    out_str[size] = '\0';
 
    BIO_free_all(bio);
    return size;
}

int main(int argc,char **argv)
{
    if(argc<4)
    {
        printf("用法：%s (-e/-d) key plaintext\n",argv[0]);
        return 0;
    }
	unsigned char key[16+1];// 128bits key (应该是真正的随机数才好)
	set_key(argv[2],key);   //设置k
	//for(int i=0;i<16;i++)
	//    printf("%d ",key[i]);
	//printf("\n");
	//return 0;
	//strncpy(key,argv[2],16);
    //key[16]='\0';
	//char text[100];
	char * text=argv[3];    //明文或者密文
	char base[1000];    //base64编码
	char ct[1000];  // 密文
	char pt[1000]; // 解密后的明文
	AES_KEY k;
    
	// single blcok test
	if(strcmp(argv[1],"-e")==0) //如果需要加密
	{
	    AES_set_encrypt_key(key, 16*8, &k);     //设置密钥
        AES_encrypt((unsigned char*)text, (unsigned char*)ct, &k);  //AES加密
        base64_encode(ct, strlen(ct),base); //base64编码加密后输出的字符串
        printf("%s",base);	    //输出最终的字符串
	}
	else
	{
	    base64_decode(text,strlen(text),ct);    //base64 解码
        AES_set_decrypt_key(key, 16*8, &k); //设置密钥
        AES_decrypt((unsigned char*)ct, (unsigned char*)pt, &k);    //AES解密
        printf("%s\n",pt);  //输出最终的字符串
	}
	return 0;
}
